using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using System.Collections;
using System.Data.SqlClient;

using System.Data;
using Utility = PHSRAG.Utility;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.CDS;
using FormsManagement = PHSRAG.Insight21.FormsManagement;
using ibex4;
using PHSRAG.Insight21.Humans;
using PHSRAG.SharePointUtility;

namespace InsightServiceUtility
{
    /// <summary>
    /// The purpose of this class is to create a single Document containing the
    /// questions, staff, and attachements from the IRB Application.
    /// </summary>
    public class IRBDocment
    {
        #region Constructor
        public IRBDocment(ICachePolicy cachePolicy)
        {
            CachePolicy = cachePolicy;
        }
        #endregion

        #region Instance Variables
        private ICachePolicy cachePolicy = null;
        private bool isSharePointDocument;
        private string filename;
        private int docid;
        #endregion

        #region Properties
        /// <summary>
        /// Cache Policy
        /// </summary>
        public ICachePolicy CachePolicy
        {
            get { return cachePolicy; }
            set { cachePolicy = value; }
        }
        public bool IsSharePointDocument
        {
            get { return isSharePointDocument; }
            set { isSharePointDocument = value; }
        }
        public string Filename
        {
            get { return filename; }
            set { filename = value; }
        }
        public int Docid
        {
            get { return docid; }
            set { docid = value; }
        }
        #endregion

        #region Constants
        public const string IbexLicenseFileName = "IbexLicenseFile";
        #endregion

        #region Methods
        /// <summary>
        /// This method will create a PDF out of the serialized QA
        /// 
        /// IBEX is used to convert the answers from XML to a PDF and
        /// the active PDF Toolkit is used to append all attachements and
        /// create bookmarks.
        /// </summary>
        /// <param name="appPath">Application Path</param>
        /// <param name="xslFilePath">Path of the xsl file used for transformation</param>
        /// <param name="includeLogo">Flag that indicates whether or not to include Logo</param>
        /// <param name="forms">The Forms collection that needs to be converted to Pdf</param>
        /// <param name="documents">Attachments (List of Document objects)</param>
        /// <returns>Document containing application</returns>
        public Document CreateDocument(string appPath, string docName, string xslFilePath, FormsManagement.Serialization.Forms forms, ArrayList documents)
        {

            Document doc = new Document(cachePolicy);
            doc.Name = docName;
            MemoryStream pdfStream = new MemoryStream();

            /*at098, KS658- logging the error specific to IBEX to track View full app issue
             */
            try
            {
                FODocument foDocument = new FODocument();
                ibex4.licensing.Generator.LicenseFileLocation = Path.Combine(appPath, Utility.Settings.GetKeyValue(IbexLicenseFileName, "License\\xmlpdf.Lic"));
                xslFilePath = Path.Combine(appPath, xslFilePath);
                using (FileStream xslStream = new FileStream(xslFilePath, FileMode.Open, FileAccess.Read))
                {
                    MemoryStream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(FormsManagement.Serialization.QuestionnaireSerializer.Serialize(forms)));
                    foDocument.generate(xmlStream, xslStream, pdfStream, false);

                }
            }
            catch (Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("IBEX PDF Creation", ex, true, Utility.ExceptionReport.ReportType.Error);
            }

            try
            {
                if (documents == null || 0 == documents.Count)
                {
                    // no attachments included
                    doc.Blob = pdfStream.ToArray();
                    return doc;
                }

                // include attachments
                APToolkitNET.Toolkit pdfToolKit = new APToolkitNET.Toolkit();

                if (null == pdfToolKit)
                {
                    throw new Exception("Unable to create Active PDF Toolkit");
                }

                ArrayList temporaryFiles = new ArrayList();
                ArrayList pdfFileCollection = new ArrayList();

                try
                {

                    // Go thru the Protocol Documents creating a temporary file for each document
                    foreach (Document document in documents)
                    {
                        TemporaryPdfFile tempPdfFile = new TemporaryPdfFile();

                        tempPdfFile.Name = Path.GetFileNameWithoutExtension(document.Name);
                        pdfFileCollection.Add(tempPdfFile);

                        if (".PDF" == document.Extension)
                        {
                            tempPdfFile.FileName = document.WriteTemporaryFile(document.Extension);
                            temporaryFiles.Add(tempPdfFile.FileName);
                            int pageCount = pdfToolKit.NumPages(tempPdfFile.FileName);

                            if (pageCount > 0)
                            {
                                tempPdfFile.PageCount = pageCount;
                            }
                            else
                            {
                                tempPdfFile.Write(ref pdfToolKit, string.Format("{0} cannot be included, may contain PDF security.", tempPdfFile.Name));
                                temporaryFiles.Add(tempPdfFile.FileName);
                            }
                        }
                        else
                        {
                            try
                            {
                                string ext = string.Empty;
                                if (null != document.PDFBlob)
                                    ext = ".PDF";
                                else
                                    ext = document.Extension;

                                string tempFilename = document.WriteTemporaryFile(ext);
                                temporaryFiles.Add(tempFilename);
                                string inputFile = Path.ChangeExtension(tempFilename, ".PDF");
                                if (null == document.PDFBlob)
                                {
                                    tempPdfFile.FileName = tempFilename;
                                    AutomationDocumentHelper.ConvertToPDF(tempFilename, inputFile, document.Extension);
                                    temporaryFiles.Add(tempPdfFile.FileName);
                                }
                                else
                                    tempPdfFile.FileName = tempFilename;

                                int pageCount = pdfToolKit.NumPages(tempPdfFile.FileName);

                                if (pageCount > 0)
                                {
                                    tempPdfFile.PageCount = pageCount;
                                }
                                else
                                {
                                    tempPdfFile.Write(ref pdfToolKit, string.Format("{0} cannot be included, may contain PDF security.", tempPdfFile.Name));
                                    temporaryFiles.Add(tempPdfFile.FileName);
                                }
                            }
                            catch (Exception ex)
                            {
                                Utility.ExceptionReport.WriteToEventLog("PDF Creation", ex, true, Utility.ExceptionReport.ReportType.Error);

                                tempPdfFile.Write(ref pdfToolKit,
                                                  string.Format("Unable to generate PDF for {0}.", tempPdfFile.Name));
                                temporaryFiles.Add(tempPdfFile.FileName);
                            }
                        }
                    }

                    // Create final output
                    // instantiate the Tool kit again due to a bug in
                    // ActivePDF that doesn't like the earlier NumPages calls
                    pdfToolKit = new APToolkitNET.Toolkit();

                    string outputFile = Path.GetTempFileName();
                    pdfToolKit.OpenOutputFile(outputFile);
                    temporaryFiles.Add(outputFile);

                    try
                    {
                        pdfToolKit.InputByteArray = pdfStream.ToArray();
                        int pageCount = pdfToolKit.NumPages("MEMORY");
                        pdfToolKit.CopyForm(0, 0);
                        pdfToolKit.CloseInputFile();

                        pdfToolKit.AddInternalLinkBookmark("Application", 1, 0, 0);
                        pdfToolKit.AddInternalLinkBookmark("Attachments", pageCount++, 0, 0);

                        foreach (TemporaryPdfFile tempPdfFile in pdfFileCollection)
                        {
                            pdfToolKit.MergeFile(tempPdfFile.FileName, 0, 0);
                            pdfToolKit.AddInternalLinkBookmark(tempPdfFile.Name, pageCount, 0, 0);
                            pageCount += tempPdfFile.PageCount;
                        }
                    }
                    finally
                    {
                        pdfToolKit.CloseInputFile();
                        pdfToolKit.CloseOutputFile();
                    }

                    FileStream fs = File.OpenRead(outputFile);
                    doc.Blob = new byte[fs.Length];
                    fs.Read(doc.Blob, 0, (int)fs.Length);
                    fs.Close();

                    return doc;
                }
                finally
                {
                    foreach (string filename in temporaryFiles)
                    {
                        try
                        {
                            File.Delete(filename);
                        }
                        catch (Exception ex)
                        {
                            // swallow this!
                            Utility.ExceptionReport.WriteToEventLog("Create Document Failure", ex, false, Utility.ExceptionReport.ReportType.Warning);
                        }
                    }
                }
            }
            finally
            {
                if (pdfStream != null)
                    pdfStream.Close();
            }
        }

        /// <summary>
        /// This method will create a PDF version of the IRB Application.
        /// It will contain answers to all questions, all staff, and optionally attachments.
        /// 
        /// IBEX is used to convert the answers from XML to a PDF and
        /// the active PDF Toolkit is used to append all attachements and
        /// create bookmarks.
        /// </summary>
        /// <param name="appPath"></param>
        /// <param name="refCodes">reference codes</param>
        /// <param name="viewApplicationType">defines if the application is "Full" which is defined by the protocol process.  Also indicates if staff and attachement information should be obtained from the Protocol</param>
        /// <returns>Document containing application</returns>
        public byte[] CreateInitialDocument(string appPath, string viewApplicationType, int protocolProcessId)
        {
            FODocument foDocument = new FODocument();
            string xslFilePath = Path.Combine(appPath, Utility.Settings.GetKeyValue("HumansXSFOFileName", ""));
            ibex4.licensing.Generator.LicenseFileLocation = Path.Combine(appPath, Utility.Settings.GetKeyValue(IbexLicenseFileName, "License\\xmlpdf.Lic"));
            string logoPath = Path.Combine(appPath, Utility.Settings.GetKeyValue("PartnersLogo", ""));

            ProtocolProcess protocolProcess = ProtocolProcess.GetProtocolProcess(Utility.DataAccess.GetConnectionString(), protocolProcessId, new NullCachePolicy(), null);
            ProtocolVersion protocolVersion = new ProtocolVersion(cachePolicy);
            protocolVersion.Load(Utility.DataAccess.GetConnectionString(), protocolProcess.GetProtocolVersionId());

            string serializedProtocolVersion = null;
            if (protocolProcess.Protocol.ModuleType == Constants.ModuleType.Animals)
            {
                serializedProtocolVersion =
                   protocolVersion.Serialize(cachePolicy, logoPath, GetStaff(viewApplicationType, protocolProcess), GetProtocolDocuments(viewApplicationType, appPath, true, protocolProcess), protocolProcess.Type);
            }
            else
            {
                serializedProtocolVersion =
                   protocolVersion.Serialize(cachePolicy, logoPath, GetStaff(viewApplicationType, protocolProcess), GetProtocolDocuments(viewApplicationType, appPath, true, protocolProcess));
            }
            if (null == serializedProtocolVersion)
            {
                throw new Exception("Unable to serialize the protocol.");
            }

            Document doc = new Document(cachePolicy);
            doc.Name = "application.pdf";
            MemoryStream pdfStream = new MemoryStream();

            /*at098, KS658- logging the error specific to IBEX to track View full app issue
             */
            try
            {
                using (FileStream xslStream = new FileStream(xslFilePath, FileMode.Open, FileAccess.Read))
                {
                    MemoryStream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(serializedProtocolVersion));
                    foDocument.generate(xmlStream, xslStream, pdfStream, false);

                    return pdfStream.ToArray();
                }
            }
            catch (Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("IBEX PDF Creation", ex, true, Utility.ExceptionReport.ReportType.Error);
                throw;
            }

        }

        /// <summary>
        /// Get staff for the process
        /// </summary>
        /// <param name="viewApplicationType">View application type </param>
        /// <param name="protocolProcess">Process for which the staffs have to be retrieved</param>
        /// <returns>Array list of staff</returns>
        public ArrayList GetStaff(string viewApplicationType, ProtocolProcess protocolProcess)
        {

            ArrayList staff = null;
            Protocol protocol = new Protocol(new NullCachePolicy());
            protocol.Load(Utility.DataAccess.ConnectionString, protocolProcess.ProtocolId);

            if (Constants.ViewApplicationType.FullUsingProtocolInformation == viewApplicationType)
            {
                staff = protocol.StudyStaffList;
            }
            else
            {
                staff = protocolProcess.GetStudyStaffForViewApp();
            }

            return staff;
        }

        /// <summary>
        /// Get all protocol document associated with the process.
        /// </summary>
        /// <param name="viewApplicationType"> View application type</param>
        /// <param name="appPath">application path</param>
        /// <param name="includeAll">flag to state whether or not to include the documents</param>
        /// <param name="protocolProcess">Process for which the documents have to be retrieved</param>
        /// <returns>Arraylist of protocol documents</returns>
        public ArrayList GetProtocolDocuments(string viewApplicationType, string appPath, bool includeAll, ProtocolProcess protocolProcess)
        {
            string logoPath = Path.Combine(appPath, Utility.Settings.GetKeyValue("PartnersLogo", ""));

            ArrayList protocolDocuments = null;
            Protocol protocol = new Protocol(cachePolicy);
            protocol.Load(Utility.DataAccess.ConnectionString, protocolProcess.ProtocolId);

            if (Constants.ViewApplicationType.FullUsingProtocolInformation == viewApplicationType)
            {
                protocolDocuments = protocol.ProtocolDocuments;
            }
            else
            {
                protocolDocuments = protocolProcess.GetProtocolDocumentsForViewApp();
            }
            if (!includeAll)
            {
                // Look for documents to include in the PDF
                RefCodes refCodes = new RefCodes(cachePolicy);
                refCodes.Load(Utility.DataAccess.GetConnectionString());
                ArrayList protocolDocumentsToInclude = new ArrayList();
                foreach (ProtocolDocument protocolDocument in protocolDocuments)
                {
                    if (protocolDocument.DocumentId > 0) // no document attached
                    {
                        RefCode refCode = refCodes.GetRefCode(FormsManagement.Constants.AttachmentType.Domain, protocolDocument.Type);

                        if (null != refCode)
                        {
                            if ("Y" == refCode[FormsManagement.Constants.AttachmentType.ApplicationIncludeAttribute])
                            {
                                protocolDocumentsToInclude.Add(protocolDocument);
                            }
                        }
                    }
                }

                //staff training certifications
                if (protocol.ModuleType == Constants.ModuleType.Animals)
                {
                    ArrayList staff = GetStaff(viewApplicationType, protocolProcess);
                    if (staff != null)
                    {
                        foreach (StaffPerson staffPerson in staff)
                        {
                            //We need to retrieve only relavant experience letters for the staff
                            FormsManagement.Serialization.Forms forms = staffPerson.Person.SerializableCertificates(cachePolicy, Utility.DataAccess.ConnectionString, protocol.SpeciesMeaning);
                            if (forms == null)
                                continue;
                            forms.ModuleType = protocol.ModuleType;
                            forms.LogoLocation = logoPath;

                            forms.StudyStaff = new ArrayList();
                            FormsManagement.Serialization.FormStudyPerson formStudyPerson = new PHSRAG.Insight21.FormsManagement.Serialization.FormStudyPerson();
                            formStudyPerson.Name = string.Format("{0}, {1}", staffPerson.LastName, staffPerson.Person.FirstName);
                            formStudyPerson.Degrees = staffPerson.Person.DegreeList;
                            forms.StudyStaff.Add(formStudyPerson);

                            //create one document for all experience letters for the staff
                            string docName = string.Format("{0}, {1}.pdf", staffPerson.LastName, staffPerson.FirstName);
                            Document doc = CreateDocument(appPath, docName, Utility.Settings.GetKeyValue("QuestionnaireAnswerToPdfXSFOFileName", "XSLFO\\TransformQuestionnaireAnswerToPDF.xsl"), forms, null);
                            ProtocolDocument proDoc = new ProtocolDocument(cachePolicy);
                            proDoc.Name = docName;
                            proDoc.ElectronicFile = doc;
                            protocolDocumentsToInclude.Add(proDoc);
                        }
                    }
                }

                protocolDocuments = protocolDocumentsToInclude;
            }
            return protocolDocuments;
        }
        /// <summary>
        /// This method is used to check and retrieve blob data for already saved VFA 
        /// </summary>
        /// <param name="protocolId"></param>
        /// <returns></returns>
        public byte[] GetVFADocument(int ProtocolProcessId, int protocolId, string type)
        {
            byte[] pdfBlob = null;
            try
            {
                object o = DBNull.Value;
                if (isSharePointDocument)
                {
                    pdfBlob = GetVFADocumentFromSharePoint(ProtocolProcessId, protocolId, type);
                }
                else
                {
                    o = Utility.DataAccess.ExecuteScalar(Utility.DataAccess.ConnectionString, "dbo.GetVFAPDFBlob",
                       Utility.DataAccess.BuildSqlParameterArray("@protocolProcessId", SqlDbType.Int, ProtocolProcessId,
                                                                 "@protocolId", SqlDbType.Int, protocolId,
                                                                 "@type", SqlDbType.VarChar, type));
                }
                if (o != DBNull.Value)
                    pdfBlob = (byte[])o;


                return pdfBlob;
            }
            catch (Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("Document.PDFBlob: Failed to load the PDF Attachment for VFA", ex, true, Utility.ExceptionReport.ReportType.Error);
                throw;
            }
            finally
            {

            }


        }

        /// <summary>
        /// This method is used to check and retrieve blob data for already saved VFA 
        /// </summary>
        /// <param name="protocolId"></param>
        /// <returns></returns>
        public byte[] GetVFADocumentFromSharePoint(int ProtocolProcessId, int protocolId, string type)
        {
            byte[] pdfBlob = null;
            try
            {


                string folderHierarchy = CreateFolderHierarchy(ProtocolProcessId, protocolId, type);

                DocumentLibrary docLibrary = new DocumentLibrary();
                pdfBlob = docLibrary.GetFileFromSharePoint(folderHierarchy);

               
            }
            catch (Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("Document.PDFBlob: Failed to load the PDF Attachment for VFA", ex, true, Utility.ExceptionReport.ReportType.Error);
               // throw;
            }
            finally
            {

            }
            return pdfBlob;
        }
        
        /// <summary>
        /// Create the url for sharepoint
        /// </summary>
        /// <param name="protocolId"></param>
        /// <param name="docId"></param>
        /// <returns></returns>
        public string CreateFolderHierarchy(int ProtocolProcessId, int protocolId, string type)
        {

            Protocol protocol = new Protocol(new NullCachePolicy());
            protocol.Load(Utility.DataAccess.ConnectionString, protocolId);

            string folderHierarchy = string.Empty;
            string moduleName = protocol.ModuleType == "H" ? "Humans" : "Animals";
            string url = Utility.Settings.GetKeyValue("SharePointBlobURL", string.Empty);
            string docLibName = Utility.Settings.GetKeyValue("DocLibName", "Document");
           

            if (string.IsNullOrEmpty(protocol.ProtocolNumber))
            {
                url += "/" + moduleName + "/" + DateTime.Now.Year + "/" + docLibName;
            }
            else
            {

                url += "/" + moduleName + "/" + protocol.ProtocolNumber.ToString().Substring(0, 4) + "/" + docLibName;
            }
            folderHierarchy = url + "/" + protocol.Id + "/" + type + "/" + ProtocolProcessId + "_" + "Application.Pdf";
            
          return folderHierarchy;
        }

    }

        #endregion

    #region Class to write the generated temporary file
    /// <summary>
    /// Class used to hold temporary PDF filenames.
    /// </summary>
    public class TemporaryPdfFile
    {
        public string Name;
        public string FileName;
        public int PageCount = 1;

        /// <summary>
        /// Writes a PDF file containing the passed text
        /// </summary>
        /// <param name="pdfToolKit"></param>
        /// <param name="text">Contents of file</param>
        public void Write(ref APToolkitNET.Toolkit pdfToolKit, string text)
        {
            try
            {
                FileName = Path.GetTempFileName();

                pdfToolKit.OpenOutputFile(FileName);
                pdfToolKit.SetFont("Helvetica|bold=1", 14, 0);
                pdfToolKit.PrintText(10, 750, text);
                pdfToolKit.CloseOutputFile();
                PageCount = 1;
            }
            catch (Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("Failed to write a PDF file using Active PDF toolkit ", ex, true, Utility.ExceptionReport.ReportType.Error);
            }
        }
    }
    #endregion
}
